feat: pluggable execution-plan scheduling and profile-guided parallel-rt placement - #1
Open
Scofield626 wants to merge 7 commits into
Open
feat: pluggable execution-plan scheduling and profile-guided parallel-rt placement#1Scofield626 wants to merge 7 commits into
Scofield626 wants to merge 7 commits into
Conversation
|
Hi! Thanks for opening this pull request. Because this is your first time contributing to this repository, please read our contributor guide: |
PlanPolicy variants now name only the ordering algorithm; measured task durations move to a separate runtime.plan_profile field. A profile-guided policy with an empty profile fails the build instead of silently reordering.
logstats gains a pipeline section: per-plan-step duration stats, the serial cycle, the slowest step, and the speedup a pipelining engine could reach. The CLI prints the bottleneck line. Schema version goes to 2.
runtime.core_placement picks how stage workers map onto the rt pool's affinity list: Spread (default, unchanged) or LongestFirst, an LPT bin-pack over plan_profile. Resolved at compile time; an all-zero profile degenerates back to Spread.
- share LOGSTATS_SCHEMA_VERSION between the exporter and rendercfg so the bump to 2 stops warning on every render - fail the build when a non-default core_placement has no rt affinity list instead of silently keeping the spread - restore the qualified cu29::config::RT_POOL path in generated code - keep one placement slot per plan step whatever the placement - warn when the --config file no longer plans the way the log was recorded - warn on an empty exported profile; use nearest-rank for --stat p99 - correct the StageStats::index and bottleneck docs; move sched-v0.md to doc/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves the
TODO(gbin): Make that heuristic pluggableincompute_runtime_plan(), then uses the same measured profile to placeparallel-rtstage workers.What
Vec<NodeId>), a shared build phase assigns copperlist slots, wires inputs, and validates. Any topological order is a correct plan, so a policy can only pick a better or worse order — it cannot corrupt wiring. The build phase rejects non-topological orders from a buggy policy.CriticalPathFirst(task_duration_ns: ...)would name the input where a variant should name the algorithm, and would force every future profile-guided algorithm to repeat the field. Kept apart, addingLongestTaskFirstorMinSlackcosts one unit variant, switching algorithm needs no re-measurement, and placement reads the same profile without going through a policy at all.TopoBfs(default) — the historical source-BFS order, byte-identical output, pinned by a golden test.CriticalPathFirst— critical-path-first list scheduling over the profile. Deterministic: ties break on node id; unmeasured tasks weigh zero.schedule-profileexporter:cu29_export <log> schedule-profile [--stat mean|p99|max]reads theprocess_timewindow each message already records and writes the pasteableplan_profile:RON value. No new instrumentation. It writes a profile, never a policy — picking the algorithm stays the user's decision.cu29_export <log> log-statsgains apipelinesection: per-plan-step duration stats,serial_cycle_ns(the serial engine's cycle),bottleneck(the slowest step, i.e. theparallel-rtcycle), andmax_pipeline_speedup = serial / bottleneck. The CLI prints one line. Schema version 1 → 2.runtime.core_placementselects howparallel-rtstage workers map onto thertpool'saffinitylist:Spread(default,stage % cores, unchanged) orLongestFirst, an LPT bin-pack over the profile. Resolved at compile time — both inputs are in the config — so the generated worker passes an already-chosen affinity slot and the hot path is untouched.A profile-guided policy or placement with an empty
plan_profilefails the build with a message pointing atschedule-profile, rather than silently falling back to another order.The profile lives inline in the config on purpose: the unified log embeds the config, so offline tools (logstats) recompute the exact same plan. Design notes and the PGO workflow are in
sched-v0.md.Why placement, and not just another policy
parallel-rtis a stage-affine pipeline: one worker per plan step, each pinned tocores[stage_index % cores.len()].CriticalPathFirstbuysparallel-rtessentially nothing. Ordering is a latency tool;parallel-rtneeds a balance tool.Hence the profile feeds three separate consumers, cheapest first: report the ceiling (done), pack cores by load (done), fuse cheap adjacent stages (still open — it breaks the stage-index = plan-index identity, so it is a larger change).
Workflow
Verification
Spreadreproduces the historical round-robin;LongestFirstbalances load; all-equal weights degenerate back toSpread; unmeasured steps weigh zero; empty profile and zero slots are rejected. Two derive-level tests cover reading thertpool and skipping when there is no affinity.cu_caterpillarfor the bottleneck report (212k samples/step, correctly fingers the 20 µs GPIO write), andcu-runtime-matrixunderparallel-rtwith a pinnedrtpool for the placement.cu_caterpillardeterminism regression passes;just clippy-nostdpasses; fmt/clippy clean.pipelinesection reports only exact stats (min/max/mean/stddev).CuDurationStatisticsis 1024 linear buckets over its configured max, so itspercentile()is meaningless at microsecond scale — an exact percentile comes fromschedule-profile --stat p99, which keeps the raw samples.RenderInput::Single(clippylarge_enum_variantafterCuConfiggrew).